﻿using System.Collections.Generic;
using NAudio.Midi;

namespace PT.NoteDetection {
    public static class MidiWriter {

        const int TicksPerQuarterNote = 480; // Ticks per quarter note

        /// <summary>Describes the MIDI format type.</summary>
        public enum MidiFormatType {
            /// <summary>
            /// A type 0 MIDI file has one track that contains all of the MIDI events for the entire song,
            /// including the song title, time signature, tempo and music events. 
            /// </summary>
            Type0 = 0,
            /// <summary>
            /// A type 1 MIDI file should have two or more tracks. The first, by convention, 
            /// contains song information such as the title, time signature, tempo, etc.  
            /// The second and following tracks contain a title, musical event data, etc. specific to that track.
            /// </summary>
            Type1 = 1,
            /// <summary>
            /// A type 2 MIDI file is sort of a combination of the contains multiple tracks, 
            /// but each track represents a different sequence which may not necessarily 
            /// be played simultaneously.
            /// This is meant to be used to save drum patterns, or other multi-pattern music sequences.
            /// </summary>
            Type2 = 2
        }

        public static void CreateMidiFile(string fileName, IList<NoteOnEvent> notes) {
            var events = new MidiEventCollection((int) MidiFormatType.Type0, TicksPerQuarterNote);
            var track = events.AddTrack();

            // Name for the whole sequence; file
            track.Add(new TextEvent("PercussionToolkit", MetaEventType.SequenceTrackName, 0));
            
            // Name for the track
            track.Add(new TextEvent("Pad", MetaEventType.TrackInstrumentName, 0));

            // Time signature
            track.Add(new TimeSignatureEvent(4, 4, 24, 8, (long) 0));

            // Key signature
            // TODO: check if I can do without this
            // track.Add(new KeySignatureEvent(0, 0, 0));

            // Tempo
            track.Add(new TempoEvent(GetMicrosecondsPerQuarterNoteFromTempo(90), 0));

            // Add notes
            foreach (var note in notes) {
                track.Add(note);
                track.Add(note.OffEvent);
            }
            
            var lastNoteTime = notes.Count == 0 ? 0 : track[track.Count - 1].AbsoluteTime;

            // Track end event
            track.Add(new MetaEvent(MetaEventType.EndTrack, 0, lastNoteTime));

            MidiFile.Export(fileName, events);
        }

        public static int GetMicrosecondsPerQuarterNoteFromTempo(int tempo) {
            return 60000000 / tempo;
        }


        /// <summary>
        /// Writes out a MIDI file.
        /// </summary>
        /// <param name="args"></param>
        public static void Main(string[] args) {
            const int ch = 16; // Channels 16 and 10 are percussion channels
            const int snare = 38; // Note 38 is Accoustic Snare 
            const int acc = 100, nor = 80, gho = 40; // Velocities: (acc)ent, (nor)mal, (gho)st

            // Paradiddle pattern: LrlrllRlrlrr
            int[] velocities = { acc, nor, nor, nor, gho, gho, acc, nor, nor, nor, gho, gho };

            // Just one duration: all notes are 16ths. TickPerQuarterNote / 4
            const int dur = TicksPerQuarterNote / 4;

            IList<NoteOnEvent> notes = new List<NoteOnEvent>();
            
            int time = 0;
            foreach(var v in velocities) {
                var note = new NoteOnEvent(time, ch, snare, v, dur);
                notes.Add(note);

                time += dur;
            }

            CreateMidiFile(@"C:\Users\Ronalds\Desktop\test.mid", notes);
        }
    }
}
